﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using Network;
using Network.Messages;

namespace Network
{
    enum NetDealayTimes
    {
        First = 0,
        Second = 1,
        Third = 2,
        Count,
    }

    public class NetworkState
    {
        public int times = 0;
        public int dealyTimeIndex = 0;
        public long lastSendTime = 0;
        public long[] dealyTime = new long[(int)NetDealayTimes.Count] { 0, 0, 0 };
        public long aveTime = 0;

        public float aveTimeSec
        {
            get
            {
                return aveTime * 0.001f;
            }
        }
    }

    /// <summary>
    /// Simple Net Delay
    /// </summary>
   /* public class SimpleDelay
    {
        public int averageDelayMillisecond = 0;
        private int[] m_delayPool = new int[5] { 100, 100, 100, 100, 100 };

        const int poolSize = 5;
        private int m_curIndex = 0;

        private long m_startTimeTick;               // m_startTimeTick is -- 100ns/周期

        private int GetAverageDelayMillisecond()
        {
            int retVal = 0;
            if (m_delayPool != null)
            {
                for (int i = 0, imax = m_delayPool.Length; i < imax; i++)
                {
                    retVal += m_delayPool[i];
                }
                return (int)(retVal / poolSize);
            }
            return 100;
        }

        public void StartCountDelay(long startTimeTick)
        {
            m_startTimeTick = startTimeTick;
        }

        public int EndCountDelay(long endTimeTick)
        {
            int curDelay = (int)((endTimeTick - m_startTimeTick) / 10000);       // 100ns -> ms
            m_curIndex++;
            if (m_curIndex >= poolSize || m_curIndex < 0)
            {
                m_curIndex = 0;
            }
            if (m_curIndex < poolSize)
            {
                m_delayPool[m_curIndex] = curDelay;
            }
            averageDelayMillisecond = GetAverageDelayMillisecond();

            return averageDelayMillisecond;
        }

        public void Reset()
        {
            m_delayPool = new int[5] { 100, 100, 100, 100, 100 };
            m_startTimeTick = DateTime.Now.Ticks;
        }
    }

    public class HeartBeater
    {
        // control vars
        const float Interval = 30.0f; // 10 second
        const float IntervalScale = 2.0f;
        float m_curTimeInterval = 0;

  //      Common.CommonHelper.Clocks m_countDownClock = null; // dis conn countdown clock -- dead line equal to 35s
//        bool m_canCountDown = false;

        // vars
        public static int heartBeaterBasedNetDelay
        {
            get
            {
                if (m_simpleDelay != null)
                {
                    return m_simpleDelay.averageDelayMillisecond;
                }
                return 0;
            }
        }

        private NetworkState m_netState = new NetworkState();
        static SimpleDelay m_simpleDelay = new SimpleDelay();               // check delay by heart beater

        public NetworkState netState
        {
            get
            {
                return m_netState;
            }
        }

        public bool Initialize()
        {

            Networker.Instance.Register(MessageType.MSG_GS2U_KeepAlive, OnGS2U_KeepAlive);
            {
                // Init time out func
                m_countDownClock = new Common.CommonHelper.Clocks(Interval * IntervalScale, true, null, () =>
                {
                    // time out callback
                    Common.UDebug.Log("Heartbeater Time Out, Disconnected!");
                    SinglePanelManger.Instance.ShowMessagePanel(MsgType.SystemPrompt, TextManager.Instance.GetString(TEXTS.NET_NETDISCONNECTED));
                });
            }

            // add net changed func
            GameSig.NetCondition.slot_NetConditionChanged += NetConditionChanged;
            return true;
        }

        public void Uninitialize()
        {
            Networker.Instance.UnRegister(MessageType.MSG_GS2U_KeepAlive, OnGS2U_KeepAlive);
            m_countDownClock = null;
            GameSig.NetCondition.slot_NetConditionChanged -= NetConditionChanged;
        }

        public void Update(float deltaTime)
        {
            m_curTimeInterval -= deltaTime;
            if (m_curTimeInterval <= 0)
            {
                m_curTimeInterval = Interval;
                long tickNow = DateTime.Now.Ticks;
                m_netState.lastSendTime = tickNow;
                NetSender.Instance.SendRequestKeepAlive();
                if (m_simpleDelay != null)
                {
                    m_simpleDelay.StartCountDelay(tickNow);
                }
            }

            if (m_countDownClock != null && m_canCountDown && m_netState.times > 0)
            {
                if (m_countDownClock.OverTime())
                {
                    Common.ULogFile.sharedInstance.Log("Heart Beat Over Time, DisConn");
                }
            }
        }

        void OnGS2U_KeepAlive(Messages.BaseMessage msg)
        {
            System.Diagnostics.Debug.WriteLine("HeartBeatAck received!");
			var msgalive = msg as GS2U_KeepAlive;
			if (msgalive != null)
			{
				LuaScriptManager.GetInstance().SetLuaServerTime(msgalive.m_timesTamp);
			}
            UpdateNetstate();
        }

        void UpdateNetstate()
        {
            long timeRec = DateTime.Now.Ticks;
            long diff = (timeRec - m_netState.lastSendTime) / TimeSpan.TicksPerMillisecond;
            long curDelayTime = diff / 2;
            m_netState.dealyTime[m_netState.dealyTimeIndex++] = curDelayTime;
            m_netState.dealyTimeIndex %= (int)NetDealayTimes.Count;
            m_netState.times ++;
            int count = Math.Min((int)NetDealayTimes.Count, m_netState.times);
            long avg = 0;
            for (int i = 0; i < count; ++i)
            {
                avg += m_netState.dealyTime[i];
            }
            m_netState.aveTime = avg / count;
            m_netState.times = count;
            // refresh countDownClock when receive HeartBeatAck
            if (m_countDownClock != null)
            {
                m_countDownClock.SetAlarm();
            }
            if (m_simpleDelay != null)
            {
                m_simpleDelay.EndCountDelay(timeRec);
            }
        }

        // net state condition func
        void NetConditionChanged(Network.ENetCondition condition)
        {
            if (condition == Network.ENetCondition.DEFAULT)
            {
                return;
            }
            // allow beat -- Passively
            if (condition == Network.ENetCondition.CONN_TO_DISCONN)
            {
                m_canCountDown = true;
                if (m_countDownClock != null)
                {
                    m_countDownClock.SetAlarm();
                }
            }
            // not allow beat -- Initiatively
            if (condition == Network.ENetCondition.DISCONN_TO_CONN)
            {
                m_canCountDown = true;
                if (m_countDownClock != null)
                {
                    m_countDownClock.SetAlarm();
                }
            }
            // not allow beat by command
            if (condition == Network.ENetCondition.DISCONN_BY_COMMAND)
            {
                m_canCountDown = false;
                if (m_countDownClock != null)
                {
                    m_countDownClock.StopAlarm();
                }
            }
            // allow beat by command
            if (condition == Network.ENetCondition.CONN_BY_COMMAND)
            {
                m_canCountDown = true;
                if (m_countDownClock != null)
                {
                    m_countDownClock.SetAlarm();
                }
            }
            if (m_simpleDelay != null)
            {
                m_simpleDelay.Reset();
            }
        }
    }*/
}
